#!/usr/bin/python
#-*-<coding=UTF-8>-*-

"""
本例展示了一个绘图程序. 程序的流程有点超出了我的理解范围.需要仔细的一行行的看懂了.
如何理解DC对象,它有哪些属性和方法.
A wx DC is a device context onto which graphics and text can be drawn. It is intended to represetn a number of output devices in a generic way, so a window can have a device context associated with it. and a printer also has a device context. In this way,the same piece of code may write to number of different device,if the device context is used as a parameter.

The wx.DC class is abstract and can not be instantiated, you must use one of the derived[diˈraivd](衍生) classes instaead.Which one will depend on the situation in which is used.
"""

import wx

class SketchWindow(wx.Window):
    def __init__(self,parent,ID):
        #Window与Frame有什么差别?
        wx.Window.__init__(self,parent,ID)
        self.SetBackgroundColour("White")
        self.color = "Black"
        self.thickness = 1
        self.pen = wx.Pen(self.color,self.thickness,wx.SOLID)
        self.lines = []
        self.curLine = []
        self.pos = (0,0)
        self.InitBuffer()
        
        #绑定<窗口>事件.
        self.Bind(wx.EVT_LEFT_DOWN,self.OnLeftDown)
        self.Bind(wx.EVT_LEFT_UP,self.OnLeftUp)
        self.Bind(wx.EVT_MOTION,self.OnMotion)
        self.Bind(wx.EVT_SIZE,self.OnSize)
        self.Bind(wx.EVT_IDLE,self.OnIdle)
        self.Bind(wx.EVT_PAINT,self.OnPaint)

    def InitBuffer(self):
        """
        DC Buffer的概念需要深刻了解. 如果要你自己去实现一个画图程序,要怎么做?
        """
        #窗口的主区域也称为客户区,即Client
        size = self.GetClientSize()
        
        #创建设备上下文
        """
        EmptyBitmap(width,height,depth=-1)
        Creates a new bitmap of the given size. A depth of -1 indicates the depth of the current screen or visual.
        Some platforms only support 1 for monochrome[[ˈmɔnəˌkrəʊm] and -1 for the current display depth.
        """
        self.buffer = wx.EmptyBitmap(size.width,size.height)
        dc = wx.BufferedDC(None,self.buffer)

        """
        使用设备上下文.
        A brush is a drawing tool for filling in areas. it is used for painting the background of
        rectangles,ellipses,etc.when drawing on a wx.DC.
        It has a colour and a style.
        """
        dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
        dc.Clear()
        self.DrawLines(dc)

        self.reInitBuffer = False

    def GetLinesData(self):
        return self.lines[:]

    def SetLinesData(self,lines):
        self.lines = lines[:]
        self.InitBuffer()
        self.Refresh()

    def OnLeftDown(self,event):
        self.curLine = []
        self.pos = event.GetPositionTuple()
        self.CaptureMouse()

    def OnLeftUp(self,event):
        if self.HasCapture():
            self.lines.append((self.color,self.thickness,self.curLine))
            self.curLine = []
            self.ReleaseMouse()

    def OnMotion(self,event):
        if event.Dragging() and event.LeftIsDown():
            dc = wx.BufferedDC(wx.ClientDC(self),self.buffer)
            self.drawMotion(dc,event)
        #理解Skip()的作用,还有事件要处理
        event.Skip()

    def drawMotion(self,dc,event):
        dc.SetPen(self.pen)
        newPos = event.GetPositionTuple()
        coords = self.pos + newPos
        self.curLine.append(coords)
        #注意，不要与下面的函数混淆，而写成dc.DrawLines(),这样程序执行不会成功
        dc.DrawLine(*coords)
        self.pos = newPos

    def OnSize(self,event):
        self.reInitBuffer = True

    def OnIdle(self,event):
        if self.reInitBuffer:
            self.InitBuffer()
            self.Refresh(False)

    def OnPaint(self,event):
        dc = wx.BufferedPaintDC(self,self.buffer)

    def DrawLines(self,dc):
        for colour,thickness,line in self.lines:
            pen = wx.Pen(colour,thickness,wx.SOLID)
            dc.SetPen(pen)
            for coords in line:
                dc.DrawLine(*coords)

    def SetColor(self,color):
        self.color = color
        self.pen = wx.Pen(self.color,self.thickness,wx.SOLID)

    def SetThickness(self,num):
        self.thickness = num
        self.pen = wx.Pen(self.color,self.thickness,wx.SOLID)

class SketchFrame(wx.Frame):
    def __init__(self,parent):
        wx.Frame.__init__(self,parent,-1,"Sketch Frame",size=(800,600))
        #画图是在window上画的,而不是在panel上. 这个吗....
        #Window是个什么东西,也可以在上面画东西吗?
        self.sketch = SketchWindow(self,-1)

if __name__ == "__main__":
    app = wx.PySimpleApp()
    frame = SketchFrame(None)
    frame.Show(True)
    app.MainLoop()



